# 第 10 章 会话与证据：JSONL、traces 与审计日志

前面九章讲机制怎么运转，这一章讲运转留下的记录。对普通用户，这些记录是「出问题去哪说理」的现场；对进阶用户，它们是理解与调优的数据源。WorkBuddy 在你的磁盘上同时记三本账：会话流水（JSONL）、执行轨迹（traces）、审计日志。三本账各记一面，合起来能回答关于「刚才到底发生了什么」的几乎一切问题。

读完本章，你应能用一条命令定位任意会话的记录文件，看懂 JSONL 里的事件类型，会查一次文件改动的历史，并知道三本账各自的边界——它们证明什么、不证明什么。

## 10.1 会话流水：事件的 ParentID 链

会话记录在 `projects/` 下按项目分组，目录名是项目路径的转写，每个会话一个 JSONL 文件（一种一行一个 JSON 对象的文本格式）。一行一个事件，实测的事件类型有六种：

| 事件类型 | 记录什么 |
|-|-|
| message | 用户消息与模型回复 |
| reasoning | 模型的思考过程 |
| function_call | 模型发起的工具调用（名称+参数） |
| function_call_result | 工具执行结果（含报错） |
| file-history-snapshot | 文件改动前的快照标记 |
| ai-title | 会话的自动命名 |

最有价值的设计是每个事件都带 `parentId`：指向上一个事件，串成链。这让「第 3 步的判断依据是什么」变得可追溯——顺着链往回走，能看到模型读到哪个文件、拿到什么结果、然后做了什么决定。**这条链就是 Agent 的「工作底稿」**，也是本书能做机制验证的根本原因（第 7 章的专家注入证据、第 5 章的「无 system 事件」结论都来自它）。

值得专门指出会话文件里**没有**的东西：系统消息。第 5 章讲过，系统提示词每次请求实时拼装、不落盘。所以会话文件记录的是「对话与行动」，不记录「规则全文」——想知道某次请求拼进了什么规则，回到模板与注入痕迹去推（第 5 章方法）。

动手，找你最近一次会话：

```
ls -lt ~/.workbuddy/projects/*/*.jsonl | head -3
```

`-lt` 按时间排序，前几个就是你最近的会话。看某个会话里模型调过哪些工具：

```
grep '"type": "function_call"' <会话文件> | grep -o '"name": "[^"]*"' | sort | uniq -c
```

（把 `` 换成上一条列出的路径。）输出是一张工具使用统计表——模型这次任务主要在干什么，一目了然。

## 10.2 文件历史：改动前的快照

`file-history-snapshot` 事件配合 `file-history/` 目录，构成 WorkBuddy 的改动保险：模型每次改你的文件之前，先存一份原状快照。官方权限文档对这层的说明是「修改已有文件前保存备份，新建文件不重复备份」。

实践意义：「它把我的文件改坏了」这句话有了客观对照——当前文件与快照一比，改动无所遁形。找回原状也简单：定位快照事件的时间戳，去 file-history 目录取对应版本。配合第 12 章的删除保护与回收站机制，这是文件安全的三重保险之一。

![三本账的分工](/workbuddy-harness/fig-13.png)

*图 10-1：三本账的分工。*

## 10.3 执行轨迹与审计：另外两本账

**traces 目录**记录执行链：每次请求生成一个轨迹文件，内部是「生成 → 工具调用 → 生成」交替的跨度序列，附带 token 消耗统计。实测一个真实工作轨迹：三百多个跨度、单次会话累计数百万 token——这个数字本身就是「Agent 任务的真实成本结构」的教学素材。轨迹证明「请求确实发生、循环确实在转」，但与传言相反，**它不记录提示词内容**——三本账里没有任何一本存拼装后的完整系统提示词。

**审计日志 `audit-log/`** 按天滚动，记录关键动作的流水（配套 spool 与 manifest 机制保证写入完整性）。它与会话流的分工：会话记对话视角，审计记系统视角——什么时间、哪个会话、执行了什么敏感操作。官方把这层归入反馈层的审计信号。

三本账的分工总结：**会话流水回答「它做了什么」，文件历史回答「它改了什么」，轨迹与审计回答「何时、多少、合不合规」**。

## 10.4 实战：两个高频排查

**「它说做了，但文件没变」。** 三步：会话文件里 grep 那个文件名，看有没有对应的 function_call；有调用看 function_call_result 是成功还是被拦（权限拦截会体现在结果或审计里）；被拦则是权限问题（第 12 章），成功但文件没变则查路径——`cwd` 字段记录了每步的工作目录，模型大概率写去了别的目录。

**「这次回答怎么这么差」。** 先看这次会话的请求侧：身份与记忆是否正常注入（对照第 4、5 章检查记忆文件有没有被污染——过时或错误条目）；再看 reasoning 链：模型是拿错了证据还是推理跳步。前者修数据，后者换模型或拆任务（第 2 章的归因框架）。

## 10.5 事件之外：providerData 里的运行时元数据

每个事件的 `providerData` 字段是一包运行时元数据，实测枚举到的键包括：`model` 与 `requestModelId`（本次请求实际用的模型——排查「模型不对」就看这里）、`messageId`、`conversationRequestId`、`traceId`（与 traces 目录的轨迹关联——两本账的连接键）、`usage` 与 `rawUsage`（token 计数）、`agent`（执行体标识，实测值为 cli）。加上每个事件都带的 `cwd`（当时的工作目录），一组字段回答了「谁、用什么模型、在哪个目录、耗了多少 token」。

两个实用场景。其一，验证模型切换是否生效：切换后发起对话，查最新事件的 `requestModelId`，与界面显示对不上就是切换没成功。其二，成本审计：`usage` 按 会话累计，找出你的 token 大户——实测一个重度工作项目的单会话累计消耗达数百万 token，这类会话值得复盘是任务本身重，还是上下文管理出了问题（比如记忆污染把无关内容反复带入）。

## 10.6 隐私交叉提示

三本账的完整也意味着：你所有的对话原文、文件路径、工作习惯，都在本地明文可查。这对你是排查利器，对能接触你电脑的人同样是。敏感场景的两个动作：重要项目结束后清理对应会话文件（现在你知道路径规律了）；分享排查截图前，注意抹掉路径与对话内容。这个话题在第 12 章展开成完整清单。

## 10.7 边界

本章边界：事件类型集合与字段来自 5.3.13 多会话抽样，新版本可能增删；「三本账不存提示词全文」是实测的否定性结论（未观测到），严格说不能排除未来版本变化；审计日志的具体字段结构未做全量解析，本章只建立其定位与分工。

机制部分到此收束。下一章进入连接世界的一环：MCP 与连接器——你的 WorkBuddy 和外部工具之间的那道门。
